﻿// C++11 -- 引用折叠和完美转发的使用和理解


#include <iostream>
#include <string>
#include "list.h"
using namespace std;



template <class T>
void f1(const T& a)
{}

template <class T>
void f2(const T&& a)
{}


//引用折叠基本语法的使用
//引用折叠指的是引用的引用会发生折叠的现象
//引用折叠记住一个口诀 --- 只有右碰右是右 , 其余是左
void Test01()
{
	int a = 1; // a 是一个左值
	int& b = a; // 左值的引用

	//不能直接写引用的引用 , 必须 typedef 
	typedef int& lefrefce; // 左引用 
	typedef int&& rgtrefce;// 右引用

	//这里写一个函数模版来印证规则

	// 1. 这里传参数 int , 函数模版 T 为 int 
	// 模版会实例化为 - void f1(int&&) , 即是右值引用 ,所以只能传右值
	f1<int>(1); // ok
	f1<int>(a); // ok

	//左碰左 - 左引用
	f1<int&>(a);//ok
	//f1<int&>(1);//err

	//右碰左 -- 左
	f1<int&&>(a);//ok
	//f1<int&&>(1);//err

	//右碰右 -- 右引用
	f2<int&&>(1); // ok
	//f2<int&&>(a); // err

}




//这个叫 *** 万能引用 *** , 因为可能是左值引用 , 可能是右值引用
template <class T>
void func(T&& d)
{
	int a = 0;
	//T x = a;
	//x++;
	cout << &a << endl;
	//cout << &x << endl << endl;
	
	
}


//引用折叠场景1
void Test02()
{
	int a = 2;

	//默认是右值引用 , 所以只能传右值
	func<int>(10);

	//左碰右是左 , 所以是左值引用
	func<int&>(a);

	//右碰右是右 , 所以是右引用
	func<int&&>(1); // T x = a;报错 

	// 左值 move 后可以传右值引用
	func<int&&>(move(a));
}




//完美转发
// forward<T>(x);
//涉及嵌套传本质属性的就可以用
void Test03()
{
	//int a = 1;
	//GJG::list<string> ls;
	//string st("1111");

	//插入左值 -- 走左值版本
	//ls.push_back(st); 
	//相应的 insert / list_node 都会走左值版本


	//cout << endl;

	//插入右值
	//ls.push_back(string("22222")); // 插入一个匿名对象为右值
	//这里本来期望的是插入的右值 
	// insert  / list_node 会走右值版本
	// **** 但是 **** 并没有 , 因为右值的本质属性是左值 , 所以要完美转发保留其属性

}



void Fun(int& x) { cout << "左值引用" << endl; }

void Fun(const int& x) { cout << "const 左值引用" << endl; }

void Fun(int&& x) { cout << "右值引用" << endl; }

void Fun(const int&& x) { cout << "const 右值引用" << endl; }

//这是一个万能引用
template<class T>
void Function(T&& t)
{
	//这里没有用完美转发 , 发现走的全是左值版本 , 因为右值的属性是左值 , 左值也是左值
	//所以一直都是走左值版本
	//Fun(t);
	

	//这里完美转发保持原有的属性
	Fun(forward<T>(t));
} 

//涉及引用折叠
void Test04()
{
	// 10 为右值 -- 编译器推导为 int 模板实例化为void Function(int&& t)
	Function(10); // 右值

	int a = 0;
	// a是左值，推导出T为int&，引用折叠，模板实例化为void Function(int& t)

	Function(a); // 左值
	// std::move(a)是右值，推导出T为int，模板实例化为void Function(int&& t)


	Function(std::move(a)); // 右值

	const int b = 8;
	// b是左值，推导出T为const int&，引用折叠，模板实例化为void Function(const int&t)
	Function(b); // const 左值

	// std::move(b)右值，推导出T为const int，模板实例化为void Function(const int&&t)
	Function(std::move(b)); // const 右值

}




int main()
{
	//引用折叠基本语法的使用
	//Test01();

	//引用折叠场景1
	//Test02();

	//完美转发
	//意思就是保留原来的属性

	//Test03();

	Test04();

	return 0;
}